package com.dyna.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.dyna.constants.SysConstant;
import com.dyna.core.exception.CustomException;
import com.dyna.core.utils.DateUtil;
import com.dyna.core.utils.PageUtil;
import com.dyna.domain.DefinitionsInfo;
import com.dyna.domain.DeploymentEntity;
import com.dyna.domain.TaskSheet;
import com.dyna.domain.req.PageParam;
import com.dyna.domain.resp.PageResult;
import com.dyna.service.FlowableService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.engine.*;
import org.flowable.engine.repository.*;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhoucaiwang
 */

@Slf4j
@Service
public class FlowableServiceImpl implements FlowableService {

    @Resource
    private ProcessEngine processEngine;

    @Override
    public String deploy(String bpmnFile,String flowName) {
        // 流程部署
        RepositoryService repositoryService = processEngine.getRepositoryService();
        DeploymentBuilder deployment = repositoryService.createDeployment();
        // 部署流程图
        bpmnFile = StrUtil.format("template/{}.xml", bpmnFile);
        Deployment deploy = deployment.addClasspathResource(bpmnFile).name(flowName).deploy();
        // 流程id
        return deploy.getId();
    }

    @Override
    public PageResult<DeploymentEntity> queryDeploys(String name) {
        PageParam pageParam = PageUtil.getPageParam();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery();

        if (StrUtil.isNotBlank(name)) {
            deploymentQuery.deploymentName(name);
        }

        long count = deploymentQuery.count();
        List<Deployment> list = deploymentQuery.orderByDeploymentTime().desc().listPage(pageParam.getPageNum() - 1,pageParam.getPageSize());
        List<DeploymentEntity> deploymentEntities = list.stream().map(it -> BeanUtil.copyProperties(it, DeploymentEntity.class)).collect(Collectors.toList());
        return new PageResult<>(deploymentEntities,count);
    }

    @Override
    public PageResult<DefinitionsInfo> definition(String deployId) {
        PageParam pageParam = PageUtil.getPageParam();
        // 流程定义
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
        if (StrUtil.isNotBlank(deployId)) {
            definitionQuery.deploymentId(deployId);
        }
        long count = definitionQuery.count();
        List<ProcessDefinition> processDefinitions = definitionQuery.orderByDeploymentId().desc().listPage(pageParam.getPageNum(), pageParam.getPageSize());
        List<DefinitionsInfo> definitionsInfos = processDefinitions.stream()
                .map(it -> BeanUtil.copyProperties(it, DefinitionsInfo.class))
                .sorted(Comparator.comparing(DefinitionsInfo::getDeploymentId))
                .collect(Collectors.toList());
        return new PageResult<>(definitionsInfos,count);
    }

    @Override
    public String createTask(TaskSheet taskSheet, String id) {
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //创建工单任务
        Map<String, Object> variable = BeanUtil.beanToMap(taskSheet);
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(id, variable);

        Assert.notNull(processInstance, SysConstant.DEFAULT_NULL_MESSAGE);
        return processInstance.getId();
    }

    @Override
    public PageResult<TaskSheet> queryTask(String id) {
        PageParam pageParam = PageUtil.getPageParam();
        List<TaskSheet> taskSheets = new ArrayList<>();

        //查询任务
        TaskService taskService = processEngine.getTaskService();
        TaskQuery taskQuery = taskService.createTaskQuery();
        TaskQuery query = taskQuery.processDefinitionId(id);
        // 任务数量
        long count = query.count();
        // 任务
        List<Task> tasks = query.includeProcessVariables().listPage(pageParam.getPageNum() - 1, pageParam.getPageSize());
        // 解析任务
        for (Task task : tasks) {
            Map<String, Object> processVariables = task.getProcessVariables();
            ObjectMapper objectMapper = new ObjectMapper();
            String writeValueAsString;
            try {
                writeValueAsString = objectMapper.writeValueAsString(processVariables);
                TaskSheet taskSheet = objectMapper.readValue(writeValueAsString, TaskSheet.class);
                taskSheet.setTaskId(task.getId());
                taskSheet.setProcessInstanceId(task.getProcessInstanceId());
                taskSheet.setAssignee(task.getAssignee());
                taskSheet.setCreateTime(DateUtil.fromDate(task.getCreateTime()));
                taskSheets.add(taskSheet);
            } catch (JsonProcessingException e) {
                log.error(e.getMessage(), e);
            }
        }
        return new PageResult<>(taskSheets,count);
    }

    @Override
    public void compileTask(String taskId,HashMap<String,Object> map) {
        try {
            TaskService taskService = processEngine.getTaskService();
            taskService.complete(taskId,map);
        }catch (FlowableObjectNotFoundException e) {
            throw new CustomException("任务不存在");
        }
    }

    @Override
    public PageResult<TaskSheet> queryHistoryTask(String id) {
        PageParam pageParam = PageUtil.getPageParam();
        List<TaskSheet> taskSheets = new ArrayList<>();
        HistoryService historyService = processEngine.getHistoryService();
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
        long count = historicTaskInstanceQuery.count();
        List<HistoricTaskInstance> list = historicTaskInstanceQuery.includeProcessVariables()
                .finished()
                .listPage(pageParam.getPageNum() - 1,pageParam.getPageSize());
        for (HistoricTaskInstance historicTaskInstance : list) {
            Map<String, Object> processVariables = historicTaskInstance.getProcessVariables();
            ObjectMapper objectMapper = new ObjectMapper();
            String writeValueAsString;
            try {
                writeValueAsString = objectMapper.writeValueAsString(processVariables);
                TaskSheet taskSheet = objectMapper.readValue(writeValueAsString, TaskSheet.class);
                taskSheet.setTaskId(historicTaskInstance.getId());
                taskSheet.setProcessInstanceId(historicTaskInstance.getProcessInstanceId());
                taskSheet.setAssignee(historicTaskInstance.getAssignee());
                taskSheet.setCreateTime(DateUtil.fromDate(historicTaskInstance.getEndTime()));
                taskSheets.add(taskSheet);
            } catch (JsonProcessingException e) {
                log.error(e.getMessage(), e);
            }        }
        return new PageResult<>(taskSheets,count);
    }



    @Override
    public void delTask(String processInstanceId,String reason) {
        /*
        1. 停止相关的流程实例：在删除任务之前，你需要停止与该任务相关的流程实例。你可以通过调用Flowable引擎的`runtimeService`对象的`deleteProcessInstance`方法来停止流程实例。这将导致相关任务被取消并且可以被删除。
        2. 检查相关的流程定义：如果任务无法被删除，可能是因为相关的流程定义被部署在Flowable引擎中。你需要先删除与任务相关的流程定义，然后再删除任务。你可以使用`repositoryService`对象的`deleteDeployment`方法来删除流程定义。
         */
        RuntimeService runtimeService = processEngine.getRuntimeService();
        runtimeService.deleteProcessInstance(processInstanceId,reason);
    }

    @Override
    public void delHistoryTask(String processInstanceId) {
        HistoryService historyService = processEngine.getHistoryService();
        historyService.deleteHistoricProcessInstance(processInstanceId);
    }

}

